package main

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"log"
	"net/http"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
)

var BaseUrl string

// ServerIp CC-VIDEO 平台 IP
const ServerIp = "127.0.0.1"

// ServerPort 服务端口号
const ServerPort = "8971"

// ConvertHandler 任务待处理队列
var ConvertHandler = InitQueue()

type ReqResult struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

func main() {
	_, fullFilename, _, _ := runtime.Caller(0)
	BaseUrl = path.Dir(fullFilename) + "/resources/video"
	fs := http.FileServer(http.Dir(BaseUrl))

	// 映射视频资源
	http.HandleFunc("/map/videoPath/", func(w http.ResponseWriter, r *http.Request) {
		// 设置跨域请求头
		w.Header().Set("Access-Control-Allow-Origin", "*")

		// 将请求转发到实际的文件服务器
		http.StripPrefix("/map/videoPath/", fs).ServeHTTP(w, r)
	})

	// 启动监听 go 程
	go listenQueue()

	defer GoWorkerPool.Stop()
	http.HandleFunc("/convert/video", handleConvertReq)
	log.Println("CC-VIDEO 转码服务已启动")
	log.Fatal(http.ListenAndServe(":"+ServerPort, nil))
}

// 将转码请求加入任务处理队列
func handleConvertReq(writer http.ResponseWriter, reader *http.Request) {

	// POST请求
	if reader.Method != "POST" {
		writer.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	// 获取 POST携带的参数
	mp4Path := reader.FormValue("mp4Path")

	// 加入任务处理队列
	ConvertHandler.Enqueue(mp4Path)

	resp := ReqResult{
		Code: 200,
		Msg:  "成功",
		Data: nil,
	}

	err := json.NewEncoder(writer).Encode(resp)
	if err != nil {
		log.Printf("服务响应失败: %s", err.Error())
		return
	}
}

// 调用本地工具，将 mp4 格式视频转换为 m3u8 格式
func convertVideo(videoPath string) {
	mp4PathSplit := strings.Split(videoPath, string(filepath.Separator))
	mp4FileName := mp4PathSplit[len(mp4PathSplit)-1]
	m3u8FileName := strings.Split(mp4FileName, ".")[0]

	hashed := hashFileName(m3u8FileName)
	m3u8FileOutput := filepath.Join(BaseUrl, hashed+".m3u8")

	cmd := exec.Command("ffmpeg", "-i", videoPath, "-c:v",
		"libx264", "-preset", "fast", "-c:a", "aac", "-b:a", "128k", "-hls_time", "10",
		"-hls_list_size", "0", "-hls_segment_filename", filepath.Join(BaseUrl, hashed+"_%d.ts"), "-f", "hls", m3u8FileOutput)

	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("视频转码失败: %s\n详情内容: %s\n", err.Error(), string(out))
		return
	}
	log.Println("处理一条转码请求")
	log.Println("视频地址：" + videoPath)
	log.Println("输出地址: " + m3u8FileOutput)
}

// 计算文件哈希
func hashFileName(input string) string {
	hash := sha256.New()
	hash.Write([]byte(input))
	hashBytes := hash.Sum(nil)
	return hex.EncodeToString(hashBytes)
}

// 监听任务处理队列是否有任务
func listenQueue() {
	for {
		if !ConvertHandler.QueueIsEmpty() && GoWorkerPool.HasAvailableResource() {
			val, ok := ConvertHandler.Dequeue()
			if ok {
				<-GoWorkerPool.Resource
				task := Task{convertVideo, val.(string)}
				GoWorkerPool.Tasks <- task
				GoWorkerPool.Resource <- 1
			}
		}
	}
}

// 调用本地工具，将 mp4 格式视频转换为 m3u8 格式并返回地址
// 如果想要获取映射地址，选这个
//func convertVideoM3u8(writer http.ResponseWriter, reader *http.Request) {
//
//	// POST请求
//	if reader.Method != "POST" {
//		writer.WriteHeader(http.StatusMethodNotAllowed)
//		return
//	}
//
//	// 获取 POST携带的参数
//	mp4Path := reader.FormValue("mp4Path")
//	mp4PathSplit := strings.Split(mp4Path, string(filepath.Separator))
//	mp4FileName := mp4PathSplit[len(mp4PathSplit)-1]
//	m3u8FileName := strings.Split(mp4FileName, ".")[0]
//
//	hashed := hashFileName(m3u8FileName)
//	m3u8FileOutput := filepath.Join(BaseUrl, hashed+".m3u8")
//
//	cmd := exec.Command("ffmpeg", "-i", mp4Path, "-c:v",
//		"libx264", "-preset", "fast", "-c:a", "aac", "-b:a", "128k", "-hls_time", "10",
//		"-hls_list_size", "0", "-hls_segment_filename", filepath.Join(BaseUrl, hashed+"_%d.ts"), "-f", "hls", m3u8FileOutput)
//
//	out, err := cmd.CombinedOutput()
//	if err != nil {
//		response := ReqResult{
//			Code: http.StatusInternalServerError,
//			Msg:  "服务器异常",
//			Data: nil,
//		}
//		json.NewEncoder(writer).Encode(response)
//		log.Printf("视频转码失败: %s\n详情内容: %s\n", err.Error(), string(out))
//		return
//	}
//
//	resp := ReqResult{
//		Code: 200,
//		Msg:  "视频转换成功",
//		Data: "http://" + ServerIp + ":" + ServerPort + "/map/videoPath/" + hashed + ".m3u8",
//	}
//	log.Println("处理一条转码请求")
//	log.Println("视频地址：" + mp4Path)
//	log.Println("输出地址: " + m3u8FileOutput)
//
//	err = json.NewEncoder(writer).Encode(resp)
//	if err != nil {
//		log.Printf("服务响应失败: %s", err.Error())
//		return
//	}
//}
